﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using XGame.Tools.Graphics;
using XGame.Tools.PathFind;
using Microsoft.Xna.Framework.Input;
using XGame.Tools;

namespace XGame.Class
{
    public class Map1
    {
        private byte[,] matrix = new byte[1024, 1024]; //寻路用二维矩阵
        private int gridSize = 20; //单位格子大小
        private Texture2D background;
        private PathFinderFast pathFinder;
        private Vector2 mouseClickVector;
        private Vector2 positionVector;
        private Stack<Vector2> pathStack;
        private Vector2 _speedVector;
        private ButtonState preState;
        private Game game;

        private void ResetMatrix()
        {
            for (int y = 0; y < matrix.GetUpperBound(1); y++)
            {
                for (int x = 0; x < matrix.GetUpperBound(0); x++)
                {
                    //默认值可以通过(非障碍物)在矩阵中用1表示
                    matrix[x, y] = 1;
                }
            }
            //构建障碍物(举例)
            for (int i = 0; i < 18; i++)
            {
                //障碍物在矩阵中用0表示
                matrix[i, 12] = 0;
            }
        }

        public Map(Game game)
        {
            positionVector = Vector2.Zero;
            this.game = game;
            this.ResetMatrix();

            pathFinder = new PathFinderFast(matrix);
            pathFinder.Formula = HeuristicFormula.Manhattan; //使用我个人觉得最快的曼哈顿A*算法
            pathFinder.HeavyDiagonals = true; //使用对角线移动
            pathFinder.HeuristicEstimate = 0;
        }

        public bool ExistPath(Vector2 from, Vector2 to)
        {
            return pathFinder.FindPath(from / gridSize, to / gridSize) != null;
        }

        public void LoadContent(ContentManager content)
        {
            background = content.Load<Texture2D>(@"Image\Map\3\Map\Map4");
        }

        public void Update(bool isActive, GameTime gameTime, Sprite sprite)
        {
            MouseState state = Mouse.GetState();
            if (preState == ButtonState.Pressed && state.LeftButton == ButtonState.Released && isActive)
            {
                if (this.ExistPath(this.positionVector + sprite.PositionVector, this.positionVector + new Vector2(state.X, state.Y)) == true)
                {
                    mouseClickVector = this.positionVector + new Vector2(state.X, state.Y);
                    sprite.State = AniPic.State.Run;
                    pathStack = null;
                }
            }
            if (sprite.State == AniPic.State.Run)
            {
                //直线移动
                Vector2 distance = mouseClickVector - sprite.PositionVector - this.positionVector;
                if (distance == Vector2.Zero || distance.Length() / sprite.Speed <= 1 || (pathStack != null && pathStack.Count == 0))
                {
                    this.positionVector += distance;
                    //如果不是完全重合，需要得出速度矢量对方向作出调整，
                    if (distance != Vector2.Zero)
                    {
                        distance.Normalize();
                        sprite.SpeedVector = distance * sprite.Speed;
                    }
                    //如果距离过小，直接移动过去。
                    //this.positionVector = mouseClickVector - sprite.PositionVector;
                    sprite.State = AniPic.State.Stand;
                    pathStack = null;
                }
                else
                {
                    distance.Normalize();
                    sprite.SpeedVector = distance * sprite.Speed;
                    Vector2 tmp = this.positionVector + sprite.PositionVector + sprite.SpeedVector;
                    if (pathStack == null && this.IsObstacle(tmp.X, tmp.Y) == false)
                    {
                        //直线移动
                        this.positionVector += sprite.SpeedVector;
                        _speedVector = sprite.SpeedVector;
                    }
                    else
                    {
                        if (pathStack == null)
                        {
                            pathStack = this.GetPathStack(this.positionVector + sprite.PositionVector, mouseClickVector);
                        }
                        if (pathStack.Peek() == this.positionVector + sprite.PositionVector)
                            pathStack.Pop();
                        //A*移动
                        sprite.SpeedVector = pathStack.Peek() - this.positionVector - sprite.PositionVector;
                        sprite.SpeedVector = Vector2.Normalize(sprite.SpeedVector);
                        sprite.SpeedVector *= sprite.Speed;
                        this.positionVector += sprite.SpeedVector;
                        if (Vector2.Distance(this.positionVector + sprite.PositionVector, pathStack.Peek()) < sprite.SpeedVector.Length())
                        {
                            pathStack.Pop();
                        }
                    }
                }
                sprite.Direction = Utility.GetDirectionByTan(Vector2.Zero, sprite.SpeedVector);
                Vector2 move = Vector2.Zero;
                int screenwidth = this.game.Window.ClientBounds.Width;
                int screenheight = this.game.Window.ClientBounds.Height;
                if (positionVector.X < 0)
                {
                    move.X = positionVector.X;
                    positionVector.X = 0;
                }
                else if (positionVector.X > this.background.Width - screenwidth)
                {
                    move.X = positionVector.X - this.background.Width + screenwidth;
                    positionVector.X = this.background.Width - screenwidth;
                }
                else if (sprite.PositionVector.X < screenwidth / 2)
                {
                    if (sprite.PositionVector.X + positionVector.X > screenwidth / 2)
                    {
                        move.X = screenwidth / 2 - sprite.PositionVector.X;
                        positionVector.X = sprite.PositionVector.X + positionVector.X - screenwidth / 2;
                    }
                    else
                    {
                        move.X = positionVector.X;
                        positionVector.X = 0;
                    }
                }
                else if (sprite.PositionVector.X > screenwidth / 2)
                {
                    float tmp = this.background.Width - screenwidth - this.positionVector.X;
                    if (tmp < sprite.PositionVector.X - screenwidth / 2)
                    {
                        move.X = -tmp;
                        this.positionVector.X = this.background.Width - screenwidth;
                    }
                    else
                    {
                        move.X = screenwidth / 2 - sprite.PositionVector.X;
                        this.positionVector.X = this.positionVector.X + sprite.PositionVector.X - screenwidth / 2;
                    }
                }
                if (positionVector.Y < 0)
                {
                    move.Y = positionVector.Y;
                    positionVector.Y = 0;
                }
                else if (positionVector.Y > this.background.Height - screenheight)
                {
                    move.Y = positionVector.Y - this.background.Height + screenheight;
                    positionVector.Y = this.background.Height - screenheight;
                }
                else if (sprite.PositionVector.Y < screenheight / 2)
                {
                    if (sprite.PositionVector.Y + positionVector.Y > screenheight / 2)
                    {
                        move.Y = screenheight / 2 - sprite.PositionVector.Y;
                        positionVector.Y = sprite.PositionVector.Y + positionVector.Y - screenheight / 2;
                    }
                    else
                    {
                        move.Y = positionVector.Y;
                        positionVector.Y = 0;
                    }
                }
                else if (sprite.PositionVector.Y > screenheight / 2)
                {
                    float tmp = this.background.Height - screenheight - this.positionVector.Y;
                    if (tmp < sprite.PositionVector.Y - screenheight / 2)
                    {
                        move.Y = -tmp;
                        this.positionVector.Y = this.background.Height - screenheight;
                    }
                    else
                    {
                        move.Y = screenheight / 2 - sprite.PositionVector.Y;
                        this.positionVector.Y = this.positionVector.Y + sprite.PositionVector.Y - screenheight / 2;
                    }
                }
                sprite.PositionVector += move;
            }
            preState = state.LeftButton;
        }

        public void Draw(DrawingContext drawingContext, SpriteFont font)
        {

            drawingContext.DrawTexture(this.background, new Rectangle((int)-positionVector.X, (int)-positionVector.Y, this.background.Width, this.background.Height), Color.White);
            drawingContext.DrawText(font, string.Format("X:{0},Y:{1}", this.positionVector.X, this.positionVector.Y), new Vector2(0, 50), Color.Yellow);
            drawingContext.DrawText(font, string.Format("X:{0},Y:{1}", this.mouseClickVector.X - this.positionVector.X, this.mouseClickVector.Y - this.positionVector.Y), new Vector2(0, 100), Color.Yellow);
            for (int i = 0; i < this.background.Width; i += gridSize)
            {
                for (int j = 0; j < this.background.Height; j += gridSize)
                {
                    if (matrix[i / gridSize, j / gridSize] != 0)
                    {
                        //drawingContext.DrawRectangle(new Rectangle(i, j, gridSize, gridSize), Color.WhiteSmoke);
                    }
                    else
                        drawingContext.DrawRectangle(new Rectangle((int)(i - this.positionVector.X), (int)(j - this.positionVector.Y), gridSize, gridSize), Color.Gray);
                }
            }
        }

        public bool IsObstacle(float x, float y)
        {
            return matrix[(int)x / gridSize, (int)y / gridSize] == 0;
        }

        public Stack<Vector2> GetPathStack(Vector2 from, Vector2 to)
        {
            List<PathFinderNode> path = pathFinder.FindPath(from / gridSize, to / gridSize);
            Stack<Vector2> pathStack = new Stack<Vector2>(path.Count); //定义关键帧坐标集
            for (int i = 0; i < path.Count; i++)
            {
                //从起点开始以GridSize为单位，顺序填充关键帧坐标集，并进行坐标系放大
                pathStack.Push(new Vector2(path[i].X * gridSize + from.X % gridSize, path[i].Y * gridSize + from.Y % gridSize));
            }
            return pathStack;
        }

    }
}
